﻿// 公司名称：松山湖材料实验室
// 项目名称：Micromach.Common.Micromach.Common
// 文件名称：ReflectiveHelper.cs
// 创建时间：2019/04/26/  10:12
// 创建的人： 陈琦   
// 功能描述：
// 最后修改：

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace RoboSensors.Tools
{
    /// <summary>
    /// 反射帮助类
    /// </summary>
    public static class ReflectionHelper
    {
        /// <summary>
        /// 结构转换为字符串，主要用于写日志
        /// </summary>
        /// <param name="obj">结构对象</param>
        /// <param name="isHaveDescription">是否存在描述特性</param>
        /// <returns></returns>
        public static string Model2String(this object obj, bool isHaveDescription = true)
        {
            var props = obj.GetPropertys();
            var str = string.Empty;
            if (!isHaveDescription)
            {
                foreach (var prop in props.Where(s => s.Name != "IsNotifying"))
                {
                    str += prop.Name + "=" + prop.Value + ",";
                }
            }
            else
            {
                foreach (var prop in props.Where(s => !string.IsNullOrEmpty(s.Description)))
                {
                    str += prop.Description + "=" + prop.Value + ",";
                }
            }

            return str;
        }
        /// <summary>
        /// 根据类型获取属性的参数
        /// </summary>
        /// <param name="t">类型</param>
        /// <param name="isOrderby">是否要以名称排序默认不需要</param>
        /// <returns>属性参数列表</returns>
        public static List<BasePropertyModel> GetPropertys(this Type t, bool isOrderby = false)
        {
            var result = new List<BasePropertyModel>();
            var props = isOrderby ? t.GetProperties().OrderBy(s => s.Name).ToArray() : t.GetProperties();
            foreach (var pi in props)
            {
                var name = pi.Name;//获得属性的名字,后面就可以根据名字判断来进行些自己想要的操作
                DescriptionAttribute[] attrs = (DescriptionAttribute[])pi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                string description = string.Empty;
                if (attrs.Length > 0)
                {
                    description = attrs[0].Description;
                }
                var type = pi.PropertyType;//value?.GetType() ?? typeof(object);//获得属性的类型

                result.Add(new BasePropertyModel() { Name = name, Type = type, PropertyInfo = pi, Description = description });
            }
            return result;
        }
        /// <summary>
        /// 获取某个对象的[公有属性]的名称,类型,值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="isOrderby"></param>
        /// <returns></returns>
        public static List<PropertyModel> GetPropertys<T>(this T obj, bool isOrderby = false)
        {
            var result = new List<PropertyModel>();
            if (obj == null)
            {
                return result;
            }

            Type t = obj.GetType();//获得该类的Type
            var props = isOrderby ? t.GetProperties().OrderBy(s => s.Name).ToArray() : t.GetProperties();
            foreach (var pi in props)
            {
                var name = pi.Name;//获得属性的名字,后面就可以根据名字判断来进行些自己想要的操作
                DescriptionAttribute[] attrs = (DescriptionAttribute[])pi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                string description = string.Empty;
                if (attrs.Length > 0)
                {
                    description = attrs[0].Description;
                }
                if (!pi.CanWrite)
                {
                    continue;
                }
                var value = pi.GetValue(obj);//用pi.GetValue获得值
                var type = pi.PropertyType;//value?.GetType() ?? typeof(object);//获得属性的类型
                result.Add(new PropertyModel() { Name = name, ReflectedName = pi.ReflectedType == null ? null : pi.ReflectedType.Name, Value = value, Type = type, PropertyInfo = pi, Description = description });
            }

            return result;
        }

        public static ClassModel GetClassProperty<T>(this T obj, bool isOrderby = false)
        {
            var result = new ClassModel();
            if (obj == null)
            {
                return result;
            }

            Type t = obj.GetType();//获得该类的Type
            var descs = t.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (descs.Length > 0)
            {
                var temp = ((DescriptionAttribute)descs[0]).Description;
                if (!temp.Equals("None"))
                {
                    result.Description = ((DescriptionAttribute)descs[0]).Description;
                }
            }
            result.PropertyModels = GetPropertys(obj, isOrderby);
            return result;
        }

        /// <summary>
        /// 反射创建对象
        /// </summary>
        /// <param name="libName">库名称</param>
        /// <param name="className">类名称</param>
        /// <param name="t">泛型类型</param>
        /// <param name="parameters">构造函数参数</param>
        /// <returns>要创建的对象</returns>
        public static object CreateInstance(string libName, string className, Type t = null, params object[] parameters)
        {
            if (string.IsNullOrEmpty(libName))
                throw new Exception("库名称不能为空!");
            if (string.IsNullOrEmpty(className))
                throw new Exception("类名称不能为空!");
            var fileName = libName.ToLower().EndsWith(".dll") ? libName : libName + ".dll";
            if (!FileHelper.IsExistFile(fileName))
            {
                throw new Exception(string.Format("库'{0}'没有找到!", fileName));
            }
            if (t == null)
            {
                var modelName = libName + "." + className;
                if (parameters == null || parameters.Length == 0)
                {
                    return Assembly.Load(libName).CreateInstance(modelName);
                }
                return Assembly.Load(libName).CreateInstance(modelName, true, BindingFlags.Default, null, parameters, null, null);
            }
            string typeName = libName + "." + className;
            var str = typeName + "`1," + libName;
            var type = Type.GetType(str);
            if (type == null)
                throw new Exception(string.Format("{0}获取泛型类型错误", str));
            type = type.MakeGenericType(t);
            if (parameters == null || parameters.Length == 0)
            {
                return Activator.CreateInstance(type);
            }

            return Activator.CreateInstance(t, true, BindingFlags.Default, null, parameters, null, null);
        }
        public static T CreateInstance<T>(Type t, params object[] parameters) where T : class, new()
        {
            if (t == null)
            {
                throw new Exception("类型不能为空!");
            }
            if (parameters == null || parameters.Length == 0)
            {
                return Activator.CreateInstance(t) as T;
            }
            return Activator.CreateInstance(t, true, BindingFlags.Default, null, parameters, null, null) as T;
        }

        public static object InvokeMethod(this object obj, string methodName, params object[] objs)
        {
            var t = obj.GetType();
            var mt = t.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
            if (mt != null)
            {
                return mt.Invoke(obj, objs);
            }
            return null;
        }

        public static string GetVersion()
        {
            return Assembly.GetExecutingAssembly().GetName().Version.ToString();
        }
    }
    public class ClassModel
    {
        /// <summary>
        /// 类的描述特性
        /// </summary>
        public string Description { get; set; }
        /// <summary>
        /// 类属性的参数集合
        /// </summary>
        public List<PropertyModel> PropertyModels { get; set; }

        public ClassModel()
        {
            PropertyModels = new List<PropertyModel>();
        }
    }
    public class BasePropertyModel
    {
        /// <summary>
        /// 属性名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 属性类型
        /// </summary>
        public Type Type { get; set; }
        /// <summary>
        /// 设置属性值的项
        /// </summary>
        public PropertyInfo PropertyInfo { get; set; }
        /// <summary>
        /// 描述特性
        /// </summary>
        public string Description { get; set; }

        public string ReflectedName { get; set; }
    }
    public class PropertyModel : BasePropertyModel
    {
        /// <summary>
        /// 值
        /// </summary>
        public object Value { get; set; }
    }
}